#ifndef __HTTP_REQUEST_H__
#define __HTTP_REQUEST_H__


#include <string>
#include <list>
using namespace std;

enum HttpReqMethod {
	METHOD_NONE = 0,
	/* common methods */
	METHOD_OPTIONS,
	METHOD_GET,
	METHOD_HEAD,
	METHOD_POST,
	METHOD_PUT,
	METHOD_DELETE,
	METHOD_TRACE,
	METHOD_TRACK,
	METHOD_CONNECT,
	/* WebDAV Methods */
	METHOD_COPY,
	METHOD_LOCK,
	METHOD_MKCOL,
	METHOD_MOVE,
	METHOD_PROPFIND,
	METHOD_PROPPATCH,
	METHOD_UNLOCK,
	/*Others,for custom defined*/
	METHOD_OTHER
};

#define IS_METHOD_HAS_BODY(m) ((m)==METHOD_POST||(m)==METHOD_PUT||(m)==METHOD_PROPFIND||(m)==METHOD_PROPPATCH||(m)==METHOD_LOCK)

struct HttpMethodName {
	HttpReqMethod method;
	string mstr;
	HttpMethodName():method(METHOD_NONE), mstr(""){}
	HttpMethodName(const HttpMethodName& r):method(r.method),mstr(r.mstr){}
	HttpMethodName(HttpReqMethod m, const string& s):method(m),mstr(s){}
	HttpMethodName& operator=(const HttpMethodName& r) 
		{ method=r.method; mstr=r.mstr; return *this; }
};

#define HT_MAKE_METHOD(r,s) HttpMethodName(r,string(s))

enum HttpReqField {
	REQ_NONE = 0,
    REQ_ACCEPT_CHAR,
    REQ_ACCEPT_ENC,
	REQ_ACCEPT_LAN,
	REQ_ACCEPT_TYPE,
	REQ_AUTH, 
	REQ_CACHE_CONTROL,
	REQ_CONNECTION,
	REQ_CONTENT_ENCODING,
    REQ_CONTENT_LANGUAGE,
    REQ_CONTENT_LENGTH,
	REQ_CONTENT_MD5,
	REQ_CONTENT_TYPE,
	REQ_COOKIE,
	REQ_DAV,
	REQ_DEPTH,
	REQ_DESTINATION,
	REQ_EXPECT,
	REQ_FROM,
	REQ_HOST,
	REQ_IF,
	REQ_IF_MATCH,
	REQ_IF_MOD_SINCE,
	REQ_IF_NONMATCH,
	REQ_IF_RANGE,
	REQ_IF_UNMOD_SINCE,
	REQ_LOCK_TOKEN,
	REQ_MAX_FORWARDS,
	REQ_OVERWRITE,
	REQ_PRAGMA,
	REQ_PROXY_AUTH,
	REQ_RANGE,
	REQ_REFERER,
	REQ_TE,
	REQ_TIMEOUT,
	REQ_TRANSFER_ENCODING,
    REQ_USER_AGENT,
	REQ_VIA,
	REQ_OTHER
};

struct ReqFieldName {
	HttpReqField field;
	string name;
};

#define HT_MAKE_REQ(r,s) {r,string(s)}

struct ReqFieldValue {
	HttpReqField field;
	string value;
	/*Methods*/
	ReqFieldValue():field(REQ_NONE),value("") {}
	ReqFieldValue(const ReqFieldValue& rfv)
		:field(rfv.field),value(rfv.value) {}
	ReqFieldValue(HttpReqField rf, const string& rv)
		: field(rf),value(rv) {}
	ReqFieldValue& operator=(const ReqFieldValue& rfv)
		{ field = rfv.field; value = rfv.value; return *this; }
};

#define DEFAULT_ACCEPT_TYPE "text/*,application/*,image/*,*/*"
#define DEFAULT_ACCEPT_LAN  "en-us,en,zh-cn"
#define DEFAULT_USER_AGENT  "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
#define DEFAULT_ACCEPT_ENC "deflate, gzip"

class HttpRequest {
public:
	HttpRequest();
	HttpRequest(const string& host, const string& uri, HttpReqMethod mtd=METHOD_GET);
	HttpRequest(const HttpRequest& req);
	HttpRequest& operator=(const HttpRequest& req);
	~HttpRequest();

	string ToString() const;

	void SetMethod(HttpReqMethod method);
	void SetHost(const string& host);
	void SetUri(const string& uri);
	void SetUserAgent(const string& ua);
	void SetAcceptType(const string& type);
	void SetAcceptEncoding(const string& encoding);
	void SetConnection(const string& connection);
	void SetCookie(const string& cookie);
	void SetContentType(const string& type);
	void SetContentLength(int length);
	void SetContentLength(const string& length);
	void SetReferer(const string& referer);
	void SetRange(const string& range);
	void SetAuthorization(const string& auth);
	int  SetField(HttpReqField field, const string& value);
	int  DelField(HttpReqField field);

private:
	HttpMethodName m_reqmtd;
	list<ReqFieldValue> m_fv;
	typedef list<ReqFieldValue>::iterator field_iterator;
	typedef list<ReqFieldValue>::const_iterator field_const_iterator;

	string m_host;
	string m_uri;
};

#endif //__HTTP_REQUEST_H__

